package com.hk.Mgr.web.controller.app.yingmi;

import com.hk.api.ProcessAPI;
import com.hk.api.ValidateService;
import com.hk.api.exceptions.ValidateException;
import com.hk.app.utils.YingmiOpenAPI;
import com.hk.base.BaseCtrl;
import com.hk.commons.DateUtil;
import com.hk.commons.entity.sys.SysUser;
import com.hk.commons.vo.JsonResult;
import com.hk.commons.vo.yingmi.ProfitsCustomReq;
import com.hk.commons.vo.yingmi.ProfitsQueryDTO;
import com.hk.service.sys.ISysUser;
import com.hk.yingmi.YingmiOpenAPIConstant;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by Antinomy on 17/8/24.
 */
@Controller
@RequestMapping(value = BaseCtrl.App)
public class YingmiAccountController {

    private Logger logger = LoggerFactory.getLogger(YingmiAccountController.class);

    @Autowired
    private YingmiOpenAPI openAPI;

    @Autowired
    private ISysUser sysUserService;


    @RequestMapping(value = YingmiOpenAPIConstant.YINGMI_API_ACCOUNT_INFO, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult accountInfo(HttpServletRequest request, Long userId) {
        ProcessAPI api = (jsonResult, validate) -> {
            SysUser user = openAPI.getValidatedUser(userId, validate);

            if (StringUtils.isBlank(user.getRealName())
                    || StringUtils.isBlank(user.getIdentity())) {
                throw new ValidateException("用户未绑卡");
            }


            String jsonResp = getAcctInfoJsonResponse(user);

            openAPI.processJsonResult(jsonResult, jsonResp);
        };

        return api.process(request);
    }

    @RequestMapping(value = YingmiOpenAPIConstant.YINGMI_API_ACCOUNT_STATUS, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult accountStatus(HttpServletRequest request, Long userId, String accountId) {

        ProcessAPI api = (jsonResult, validate) -> {
            validate.check("accountId", accountId);
            SysUser user = openAPI.getValidatedUser(userId, validate);

            Boolean hasBindCard = false;
            HashMap riskLevelInfo;

            String acctInfoJsonResp = getAcctInfoJsonResponse(user);
            riskLevelInfo = getRiskLevel(acctInfoJsonResp);

            String bingCardsResp = getBindCardJsonResponse(accountId, user);
            hasBindCard = checkBindCard(bingCardsResp);

            HashMap result = new HashMap();
            result.put("realName", user.getRealName());
            result.put("mobile", user.getName());
            result.put("hasBindCard", hasBindCard);
            result.put("riskLevel", riskLevelInfo);

            jsonResult.result = result;
        };

        return api.process(request);
    }

    @RequestMapping(value = YingmiOpenAPIConstant.YINGMI_API_ACCOUNT_GET_PROFITS, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getProfits(HttpServletRequest request, ProfitsQueryDTO profitsQueryDTO) {
        ProcessAPI api = (jsonResult, validate) -> {
            SysUser user = openAPI.getValidatedUser(profitsQueryDTO.getUserId(), validate);

            Map<String, String> params = new HashMap<>();
            params.put("brokerUserId", user.getName());
            params.put("accountId", profitsQueryDTO.getAccountId());

            if (StringUtils.isNoneBlank(profitsQueryDTO.getFundCode())) {
                params.put("fundCode", profitsQueryDTO.getFundCode());
            }

            if (StringUtils.isNoneBlank(profitsQueryDTO.getBeginDate())
                    && StringUtils.isNoneBlank(profitsQueryDTO.getEndDate())) {

                params.put("beginDate", profitsQueryDTO.getBeginDate());
                params.put("endDate", profitsQueryDTO.getEndDate());
            }

            String jsonResp = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.TRADE_GET_PROFITS, params, null);

            openAPI.processJsonResult(jsonResult, jsonResp);
        };

        return api.process(request);
    }

    @RequestMapping(value = YingmiOpenAPIConstant.YINGMI_API_ACCOUNT_GET_PROFITS_ONE_FUNDCODE, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getProfitsOneFund(HttpServletRequest request, ProfitsQueryDTO profitsQueryDTO) {
        ProcessAPI api = (jsonResult, validate) -> {
            String fundCode = profitsQueryDTO.getFundCode();
            validate.check("fundCode", fundCode);

            SysUser user = openAPI.getValidatedUser(profitsQueryDTO.getUserId(), validate);

            Map<String, String> params = new HashMap<>();
            params.put("brokerUserId", user.getName());
            params.put("accountId", profitsQueryDTO.getAccountId());
            params.put("fundCode", fundCode);

            if (StringUtils.isNoneBlank(profitsQueryDTO.getBeginDate())
                    && StringUtils.isNoneBlank(profitsQueryDTO.getEndDate())) {

                params.put("beginDate", profitsQueryDTO.getBeginDate());
                params.put("endDate", profitsQueryDTO.getEndDate());
            }

            String jsonResp = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.TRADE_GET_PROFITS, params, null);
//            jsonResp = getmock();

            if (hadFundData(jsonResp, fundCode)) {
                Integer startIndex = jsonResp.indexOf("[");
                Integer endIndex = jsonResp.indexOf("]") + 1;
                String content = jsonResp.substring(startIndex, endIndex);

                List fundList = openAPI.convertArrayToList(content);
                jsonResult.result = fundList;
            }
        };

        return api.process(request);
    }

    /**
     * 查询账户盈亏接口改造-统计
     *
     * @param request
     * @param profitsCustomReq
     * @return urlDesc http://59.107.26.180/showdoc/index.php?s=/2&page_id=244
     */
    @RequestMapping(value = YingmiOpenAPIConstant.YINGMI_API_ACCOUNT_GET_SUM_PROFITS, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getSumProfits(HttpServletRequest request, ProfitsCustomReq profitsCustomReq) {
        logger.info("request url:" + "/yingmiAPI/account/getSumProfits");
        ProcessAPI api = (JsonResult jsonResult, ValidateService validate) -> {
            SysUser user = openAPI.getValidatedUser(profitsCustomReq.getUserId(), validate);

            String fundCode = profitsCustomReq.getFundCode();
            validate.check("fundCode", fundCode);

            Map<String, String> params = new HashMap<>();
            params.put("brokerUserId", user.getName());
            params.put("accountId", profitsCustomReq.getAccountId());
            params.put("fundCode", fundCode);
            //params.put("brokerUserId", "18870751106");
            //params.put("accountId", "6uj63z4nh04q");

            //两年前
            Date twoYearDate = getTwoYearsAgoDate();

            String beginDate = DateUtil.DateToFormat(twoYearDate);
            String endDate = DateUtil.DateToFormat(new Date());

            if (beginDate.compareTo("2016-01-01") < 0) { //beginDate 小于 2016-01-01 前的情况
                beginDate = "2016-01-01";
            }

            params.put("beginDate", beginDate);
            params.put("endDate", endDate);
            validate.check("type", profitsCustomReq.getType());

            logger.info("parm Map = {}", params);
            String jsonResp = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.TRADE_GET_PROFITS, params, null);
            //String jsonResp = getMockTradeRecords();
            logger.info("result = {}", jsonResp);

            List<Map> fundList = null;
            if (hadFundData(jsonResp, fundCode)) {
                Integer startIndex = jsonResp.indexOf("[");
                Integer endIndex = jsonResp.indexOf("]") + 1;
                String content = jsonResp.substring(startIndex, endIndex);

                fundList = openAPI.convertArrayToList(content);
            }

            //数据为空的情况
            Map<String, Object> resultMap = new HashMap<>();
            if (fundList == null) {
                resultMap.put("profit_sum", "0.00");
                resultMap.put("last_day_profit", "0.00");
                jsonResult.result = resultMap;
                return;
            }

            //最后更新的记录交易时间，取当天时间累计加sum(profit)
            String tradeDate = fundList.get(0).get("tradeDate").toString();

            BigDecimal lastDay_profit = fundList
                    .parallelStream()
                    .filter(n -> n.get("tradeDate").equals(tradeDate))
                    .map(n -> new BigDecimal(n.get("profit").toString()))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            List<Map> notEstimatedFundList = fundList
                    .parallelStream()
                    .filter(n -> n.get("isEstimated").equals(false))
                    .collect(Collectors.toList());

            //isEstimated为false并统计profit
            BigDecimal profitSum = notEstimatedFundList
                    .parallelStream()
                    .map(n -> new BigDecimal(n.get("profit").toString()))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            String type = profitsCustomReq.getType();//0为不显示列表 1为显示列表详情
            if (type.equals("0") || !type.equals("1")) {
                //昨日收益总和（同一张卡）及 总收益
                getSumProfitsMap(resultMap, lastDay_profit, profitSum);
            }
            if (type.equals("1")) {
                //昨日收益总和（同一张卡）及 总收益
                getSumProfitsMap(resultMap, lastDay_profit, profitSum);
                resultMap.put("list_details", notEstimatedFundList);
            }

            jsonResult.result = resultMap;

        };

        return api.process(request);
    }

    /**
     * 最前两年时间
     *
     * @return date
     */
    private Date getTwoYearsAgoDate() {
        Calendar calendar = Calendar.getInstance();
        Date date = new Date(System.currentTimeMillis());
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, -2);
        date = calendar.getTime();
        return date;
    }

    private void getSumProfitsMap(Map<String, Object> resultMap, BigDecimal lastDayProfitResult, BigDecimal profitSumResult) {
        //profit 总和
        resultMap.put("profit_sum", profitSumResult.setScale(2).toString());
        //profit 最后更新的记录 profit
        resultMap.put("last_day_profit", lastDayProfitResult.setScale(2).toString());
    }

    private String getMockTradeRecords() {
        //return "{\"000509\":[{\"value\":\"0.00\",\"isEstimated\":true,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-17\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.08\",\"profit\":\"2.01\",\"profit4Dec\":\"0.0095\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.08\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-15\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.08\",\"profit\":\"1.13\",\"profit4Dec\":\"0.0300\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.07\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-17\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.07\",\"profit\":\"5.01\",\"profit4Dec\":\"0.0100\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.06\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-13\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.06\",\"profit\":\"9.01\",\"profit4Dec\":\"0.0100\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.05\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-12\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.05\",\"profit\":\"0.01\",\"profit4Dec\":\"0.0100\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.03\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-11\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.03\",\"profit\":\"0.02\",\"profit4Dec\":\"0.0200\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"0.00\",\"isEstimated\":true,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-10\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.03\",\"profit\":\"0.01\",\"profit4Dec\":\"0.0114\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.00\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-08\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.00\",\"profit\":\"0.03\",\"profit4Dec\":\"0.0300\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"0.00\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-17\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"0.00\",\"profit\":\"0.10\",\"profit4Dec\":\"0.0000\",\"shareType\":\"A\",\"shareId\":null,\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"}]}";
        return "{\"000509\":[{\"value\":\"0.00\",\"isEstimated\":true,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-17\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.08\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0095\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.08\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-15\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.08\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0300\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.07\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-17\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.07\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0100\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.06\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-13\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.06\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0100\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.05\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-12\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.05\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0100\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.03\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-11\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.03\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0200\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"0.00\",\"isEstimated\":true,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-10\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.03\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0114\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"100.00\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-08\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"100.00\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0300\",\"shareType\":\"A\",\"shareId\":\"2017090800096649\",\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"},{\"value\":\"0.00\",\"isEstimated\":false,\"nav\":\"1.0000\",\"tradeDate\":\"2017-09-17\",\"paymentMethodId\":\"7ib962y8czyq\",\"totalShare\":\"0.00\",\"profit\":\"0.00\",\"profit4Dec\":\"0.0000\",\"shareType\":\"A\",\"shareId\":null,\"fundName\":\"广发钱袋子货币\",\"fundCode\":\"000509\"}]}";
    }


    private boolean hadFundData(String jsonResp, String fundCode) {

        if (StringUtils.isBlank(jsonResp))
            return false;

        if (!jsonResp.contains(fundCode))
            return false;

        if (!jsonResp.contains("["))
            return false;

        if (!jsonResp.contains("]"))
            return false;

        return true;
    }


    private String getBindCardJsonResponse(String accountId, SysUser user) {
        // check bind card
        Map<String, String> bindCardsParams = new HashMap<>();
        bindCardsParams.put("brokerUserId", user.getName());
        bindCardsParams.put("accountId", accountId);

        return openAPI.sslGet_ByMap(YingmiOpenAPIConstant.ACCOUNT_GET_PAYMENT_METHODS, bindCardsParams, null);
    }

    private String getAcctInfoJsonResponse(SysUser user) {
        Map<String, String> params = new HashMap<>();
        params.put("accountName", user.getRealName().trim());
        params.put("identityNo", user.getIdentity());

        String jsonResp = openAPI.sslGet_ByMap(YingmiOpenAPIConstant.ACCOUNT_GET_ACCOUNT_BY_IDENTITY, params, null);

        syncUserAcctId(user, jsonResp);


        return jsonResp;
    }

    private void syncUserAcctId(SysUser user, String jsonResp) {
        if (StringUtils.isNoneBlank(user.getAccountId())) {
            return;
        }

        try {
            HashMap map = openAPI.convertToMap(jsonResp);

            if (map == null || map.get("accountId") == null) {
                return;
            }

            String accountId = map.get("accountId").toString();
            if (StringUtils.isBlank(accountId)) {
                return;
            }

            user.setAccountId(accountId);
            sysUserService.update(user);

        } catch (IOException e) {
            e.printStackTrace();
            logger.error("syncUserAcctId Error : ", e);
        }

    }


    private HashMap getRiskLevel(String acctInfoJsonResp) {
        HashMap result = new HashMap();

        try {
            HashMap resp = openAPI.convertToMap(acctInfoJsonResp);

            Object riskGrade = resp.get("riskGrade");
            Object riskGrade5 = resp.get("riskGrade5");
            Object isMinRiskGrade = resp.get("isMinRiskGrade");
            Object adequancyInfoReady = resp.get("adequancyInfoReady");

            result.put("riskGrade", riskGrade);
            result.put("riskGrade5", riskGrade5);
            result.put("isMinRiskGrade", isMinRiskGrade);
            result.put("adequancyInfoReady", adequancyInfoReady);

            if (riskGrade5 == null
                    || "null".equalsIgnoreCase(riskGrade5.toString())) {
                result.put("riskGrade5", null);
                result.put("checkRiskLevel", false);
                return result;
            }

            if (riskGrade5.toString().equals("0")) {
                result.put("riskGrade5", "0");
                result.put("checkRiskLevel", false);
                return result;
            }

            result.put("riskGrade5", riskGrade5.toString());
            result.put("checkRiskLevel", true);

        } catch (IOException e) {
            e.printStackTrace();
            result.put("riskGrade", null);
            result.put("riskGrade5", null);
            result.put("checkRiskLevel", false);
            return result;
        }

        return result;
    }

    private Boolean checkBindCard(String bingCardsResp) {

        if (!openAPI.isJsonArray(bingCardsResp)) {
            return false;
        }

        try {
            List bindCards = openAPI.convertArrayToList(bingCardsResp);

            if (bindCards.size() > 0) {
                return true;
            }


        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

        return false;
    }


//    private String getmock() {
//        StringBuilder sb = new StringBuilder();
//
//        sb.append(" {                                                     ".trim());
//        sb.append("     \"270004\": [                                       ".trim());
//        sb.append("     {                                                 ".trim());
//        sb.append("         \"value\": \"1201.29\",                           ".trim());
//        sb.append("             \"isEstimated\": false,                     ".trim());
//        sb.append("             \"nav\": \"1.0000\",                          ".trim());
//        sb.append("             \"tradeDate\": \"2015-10-22\",                ".trim());
//        sb.append("             \"paymentMethodId\": \"67td19ovohe2\",        ".trim());
//        sb.append("             \"totalShare\": \"1201.29\",                  ".trim());
//        sb.append("             \"profit\": \"0.10\",                         ".trim());
//        sb.append("             \"shareType\": \"A\",                         ".trim());
//        sb.append("             \"fundName\": \"广发货币A\",                      ".trim());
//        sb.append("             \"fundCode\": \"270004\",                     ".trim());
//        sb.append("     },                                                ".trim());
//        sb.append("     {                                                 ".trim());
//        sb.append("         \"value\": \"1201.29\",                           ".trim());
//        sb.append("             \"isEstimated\": false,                     ".trim());
//        sb.append("             \"nav\": \"1.0000\",                          ".trim());
//        sb.append("             \"tradeDate\": \"2015-10-21\",                ".trim());
//        sb.append("             \"paymentMethodId\": \"67td19ovohe2\",        ".trim());
//        sb.append("             \"totalShare\": \"1201.29\",                  ".trim());
//        sb.append("             \"profit\": \"0.13\",                         ".trim());
//        sb.append("             \"shareType\": \"A\",                         ".trim());
//        sb.append("             \"fundName\" : \"广发货币A\",                     ".trim());
//        sb.append("             \"fundCode\" : \"270004\"                     ".trim());
//        sb.append("     }                                                 ".trim());
//        sb.append("     ]                                                 ".trim());
//        sb.append(" }                                                     ".trim());
//
//        return sb.toString();
//    }

}
